package com.seanliao.nav.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Assert;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.seanliao.nav.common.domain.dto.PermissionDTO;
import com.seanliao.nav.common.domain.vo.PermissionVO;
import com.seanliao.nav.common.exception.BusinessException;
import com.seanliao.nav.entity.SysPermission;
import com.seanliao.nav.entity.SysRolePermission;
import com.seanliao.nav.mapper.SysPermissionMapper;
import com.seanliao.nav.security.MyUserDetails;
import com.seanliao.nav.service.ISysPermissionService;
import com.seanliao.nav.service.ISysRolePermissionService;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 权限表 服务实现类
 * </p>
 *
 * @author Sean_Liao
 * @since 2024-01-23
 */
@Service
@RequiredArgsConstructor
public class SysPermissionServiceImpl extends ServiceImpl<SysPermissionMapper, SysPermission> implements ISysPermissionService {

    private final ISysRolePermissionService rolePermissionService;

    /* 类型-目录 */
    public static final int TYPE_CONTENT = 0;
    /* 类型-菜单 */
    public static final int TYPE_MENU = 1;
    /* 类型-权限 */
    public static final int TYPE_PERMISSION = 2;

    @Override
    public List<SysPermission> listPermissionByRoleIds(List<Long> roleIds) {
        if (roleIds.isEmpty()) {
            return Collections.emptyList();
        }
        List<SysRolePermission> rolePermissionList = rolePermissionService.list(new LambdaQueryWrapper<SysRolePermission>().in(SysRolePermission::getRoleId, roleIds));
        if (rolePermissionList.isEmpty()) {
            return Collections.emptyList();
        }
        List<Long> permissionIds = rolePermissionList.stream().map(SysRolePermission::getPermissionId).collect(Collectors.toList());
        return this.list(new LambdaQueryWrapper<SysPermission>()
                .eq(SysPermission::getIsBan, 0)
                .in(SysPermission::getId, permissionIds));
    }

    @Override
    public List<PermissionVO> selectMenuForCurrentUser() {
        Object userDetails = SecurityContextHolder.getContext().getAuthentication().getDetails();
        if (userDetails instanceof MyUserDetails myUserDetails) {
            List<String> permissionCodes = myUserDetails.getPermissions();
            if (permissionCodes.isEmpty()) {
                return Collections.emptyList();
            } else {
                List<SysPermission> permissions = this.list(new LambdaQueryWrapper<SysPermission>()
                        .select(SysPermission::getId, SysPermission::getPid, SysPermission::getSort, SysPermission::getName, SysPermission::getIcon)
                        .eq(SysPermission::getIsBan, false)
                        .in(SysPermission::getCode, permissionCodes)
                        .in(SysPermission::getType, TYPE_CONTENT, TYPE_MENU)
                        .orderByAsc(SysPermission::getSort));
                return transferTree(permissions, 0L);
            }
        } else {
            return Collections.emptyList();
        }
    }

    @Override
    public List<PermissionVO> selectByRoleId(Long roleId) {
        List<SysRolePermission> rolePermissionList = rolePermissionService.list(new LambdaQueryWrapper<SysRolePermission>().eq(SysRolePermission::getRoleId, roleId));
        if (rolePermissionList.isEmpty()) {
            return Collections.emptyList();
        }
        List<Long> permissionIds = rolePermissionList.stream().map(SysRolePermission::getPermissionId).collect(Collectors.toList());
        List<SysPermission> permissions = this.list(new LambdaQueryWrapper<SysPermission>()
                .select(SysPermission::getId, SysPermission::getPid, SysPermission::getSort, SysPermission::getName, SysPermission::getIcon)
                .eq(SysPermission::getIsBan, false)
                .in(SysPermission::getId, permissionIds)
                .orderByAsc(SysPermission::getSort));
        return transferTree(permissions, 0L);
    }

    @Override
    public List<PermissionVO> selectMenu() {
        List<SysPermission> permissions = this.list(new LambdaQueryWrapper<SysPermission>().in(SysPermission::getType, TYPE_CONTENT, TYPE_MENU));
        return transferTree(permissions, 0L);
    }

    @Override
    public List<PermissionVO> selectPermission(Long id) {
        List<SysPermission> permissions = this.list(new LambdaQueryWrapper<SysPermission>()
                .eq(SysPermission::getPid, id)
                .eq(SysPermission::getType, TYPE_PERMISSION));
        return transferTree(permissions, id);
    }

    @Override
    public void add(PermissionDTO permissionDTO) {
        Assert.isFalse(this.count(new LambdaQueryWrapper<SysPermission>().eq(SysPermission::getName, permissionDTO.getName())) > 0,
                () -> new BusinessException("权限名称已存在"));
        // 构造实体并入库
        SysPermission permission = BeanUtil.copyProperties(permissionDTO, SysPermission.class);
        permission.setIsBan(false);
        permission.setSort(permissionDTO.getSort());
        this.save(permission);
    }

    @Override
    public void edit(PermissionDTO permissionDTO) {
        if (permissionDTO.getName() != null) {
            Assert.isFalse(this.count(new LambdaQueryWrapper<SysPermission>()
                            .eq(SysPermission::getName, permissionDTO.getName())
                            .ne(SysPermission::getId, permissionDTO.getId())
                    ) > 0,
                    () -> new BusinessException("权限名称已存在"));
        }
        SysPermission permission = BeanUtil.copyProperties(permissionDTO, SysPermission.class);
        this.updateById(permission);
    }

    @Override
    public void remove(Long permissionId) {
        Assert.isFalse(this.count(new LambdaQueryWrapper<SysPermission>().eq(SysPermission::getPid, permissionId)) > 0,
                () -> new BusinessException("存在子权限，不可删除"));
        Assert.isFalse(rolePermissionService.count(new LambdaQueryWrapper<SysRolePermission>().eq(SysRolePermission::getPermissionId, permissionId)) > 0,
                () -> new BusinessException("权限已分配，不可删除"));
        this.removeById(permissionId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void editRolePermission(Long roleId, List<Long> permissionIds) {
        // 删
        rolePermissionService.remove(new LambdaQueryWrapper<SysRolePermission>().eq(SysRolePermission::getRoleId, roleId));
        // 增
        List<SysRolePermission> addList = permissionIds.stream().map(permissionId -> {
            SysRolePermission sysRolePermission = new SysRolePermission();
            sysRolePermission.setRoleId(roleId);
            sysRolePermission.setPermissionId(permissionId);
            return sysRolePermission;
        }).collect(Collectors.toList());
        if (!addList.isEmpty()) {
            rolePermissionService.saveBatch(addList);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void editPermissionRole(Long permissionId, List<Long> roleIds) {
        // 删
        rolePermissionService.remove(new LambdaQueryWrapper<SysRolePermission>().eq(SysRolePermission::getPermissionId, permissionId));
        // 增
        List<SysRolePermission> addList = roleIds.stream().map(roleId -> {
            SysRolePermission sysRolePermission = new SysRolePermission();
            sysRolePermission.setRoleId(roleId);
            sysRolePermission.setPermissionId(permissionId);
            return sysRolePermission;
        }).collect(Collectors.toList());
        if (!addList.isEmpty()) {
            rolePermissionService.saveBatch(addList);
        }
    }

    @Override
    public void sort(List<PermissionDTO> permissionDTOList) {
        List<SysPermission> permissionList = permissionDTOList.stream().map(permissionDTO -> {
            SysPermission sysPermission = new SysPermission();
            sysPermission.setId(permissionDTO.getId());
            sysPermission.setSort(permissionDTO.getSort());
            return sysPermission;
        }).collect(Collectors.toList());
        this.updateBatchById(permissionList);
    }

    /**
     * 递归生成权限树
     */
    private List<PermissionVO> transferTree(List<SysPermission> permissions, Long parentId) {
        List<PermissionVO> resultList = new ArrayList<>();
        if (!permissions.isEmpty()) {
            permissions.forEach(permission -> {
                if (parentId.equals(permission.getPid())) {
                    PermissionVO permissionVO = new PermissionVO();
                    BeanUtil.copyProperties(permission, permissionVO);
                    List<PermissionVO> childPermission = transferTree(permissions, permission.getId());
                    permissionVO.setChildPermission(childPermission);
                    resultList.add(permissionVO);
                }
            });
        }
        // 排序
        Collections.sort(resultList);
        return resultList;
    }
}
